package sketch.seg.cd;

import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;

import sketch.ink.SampledPoint;
import sketch.ink.Stroke;

public class CDDynamicKH extends CornerDetector {

    private int K = 4;

    private double H = .9;

    private int k[] = null;

    private double rhos[] = null;

    public CDDynamicKH() {}

    public CDDynamicKH(Stroke s) {
    	super(s);
    }

    public double getH() {
        return H;
    }

    public int getK() {
        return K;
    }

    public int getK(int i) {
        if (k == null) {
            detectCorners();
        }
        if (i >= 0 && i < k.length)
            return k[i];
        return 0;
    }

    public void setK(int v, int i) {
        if (k == null || i < 0 || i > k.length)
            return;
        k[i] = v;
        clear();
    }

    public void setH(double h) {
        H = h;
        clear();
    }

    public void setK(int k) {
        K = k;
        clear();
    }

    public double getRho(int i) {
        if (rhos == null) {
//        	System.out.println("no corners and rhos");
        	detectCorners();
        }

        if (i >= 0 && i < rhos.length) {
//        	System.out.println("get rho at " + i);
//        	System.out.println("corners = " + getCorners().size());
//        	System.out.println("points = " + getPoints().size());
            return rhos[i];
        }
        return 0;
    }

    protected void detectCorners() {
    	super.detectCorners();

    	List<SampledPoint> corners = new ArrayList<SampledPoint>();

        SampledPoint[] ps = new SampledPoint[getPoints().size()];
        getPoints().toArray(ps);

        rhos = new double[ps.length];
        if (k == null || k.length != ps.length) {
            k = new int[ps.length];
            for (int i = 0; i < k.length; i++) {
                k[i] = -1;
                rhos[i] = -1;
            }
        }

        for (int i = 0; i < ps.length; i++) {
            double max_rho = -1;
            int max_k = 3;

            if (k[i] != -1) {
                rhos[i] = relativeRho(ps, i, k[i]);
            } else {

	            for (int j = K; //j < ps.length / 20 &&
	                             j < 12; j++) {
	//			int j = 3;
	                double rho = relativeRho(ps, i, j);
	                if (max_rho < rho) {
	                    max_k = j;
	                    max_rho = rho;
	                }
	            }
	            rhos[i] = max_rho;
	            k[i] = max_k;
            }
        }

//		CDParameterList.get().appendParameter(cdp);

        int maxIndex = 0;
        double maxRho = -1;
        int state = 0;
        for (int i = 0; i < rhos.length; i++) {
            if (rhos[i] > H && state == 0) {
                state = 1;
                maxRho = rhos[i];
                maxIndex = i;
            } else if (rhos[i] > H && state == 1) {
                if (rhos[i] > maxRho) {
                    maxRho = rhos[i];
                    maxIndex = i;
                }
            } else if (rhos[i] < H && state == 1) {
                state = 0;
                corners.add(ps[maxIndex]);
                maxRho = -1;
                maxIndex = 0;
            }
        }
        if (state == 1)
            corners.add(ps[maxIndex]);

        setCorners(corners);
    }

    private double relativeRho(SampledPoint[] ps, int I, int K) {
        if (I < K || I >= ps.length - K)
            return 0;

        Line2D line = new Line2D.Double(ps[I-K].getX(), ps[I-K].getY(),
                ps[I+K].getX(), ps[I+K].getY());

        double dis = 0;
        double len = line.getP1().distance(line.getP2());
        for (int i = I - K + 1; i < I + K; i++) {
            dis += Math.abs(line.ptLineDist(ps[i].toPoint2D()));
        }
//		System.out.println(dis + ":" + len);
        return Math.abs(dis/len);
    }

}
